// Ticker module. There's a master game ticker, which you can access through
//   Ticker.master. You can also instantiate other Ticker objects if you
//   feel like it.

package src {
    import flash.utils.Timer;
    import flash.utils.getTimer;
    import flash.events.TimerEvent;
    public class Ticker {
        public var fpsGoal:Number;
        public var fps:Number;
        public var dt:Number;
        protected var dtMax:Number;
        public var t:Number;
        protected var clock:Timer;
        protected var tickTimes:Array;
        protected var callback:Function;
        protected var tickRecords:int;
        protected var lastTick:int;
        public static var master:Ticker = new Ticker(60);
        
        public function Ticker(fps_:Number, callback_:Function=null) {
            fpsGoal = fps_;
            callback = callback_;
            
            clock = new Timer(1000. / fpsGoal);
            clock.addEventListener(flash.events.TimerEvent.TIMER, tick)
            clock.start();

            tickRecords = 100;
            tickTimes = new Array();
            for (var j:int = 0; j < tickRecords; ++j)
                tickTimes.push(-1);

            lastTick = 0;
            dtMax = 0.1;
            t = 0;
        }

        // TODO: figure out getters and setters
        public function setCallback(callback_:Function=null):void {
            callback = callback_;
        }

        protected function tick(evt:TimerEvent):void {
            var now:int = getTimer();
            var k:int = clock.currentCount % tickRecords;
            dt = Math.min(0.001 * (now - lastTick), dtMax);
            t += dt;
            if (tickTimes[k] < 0) {
                fps = (k+1) * 1000. / (now - tickTimes[0]);
            } else {
                fps = tickRecords * 1000. / (now - tickTimes[k]);
            }
            tickTimes[k] = now;
            lastTick = now;
            if (callback !== null) {
                callback(dt);
            }
        }

        // A string that gives the framerate to a manageable precision
        // 20+fps: zero decimals
        // 2-20fps: one decimal
        // <2fps: two decimals
        public function fpsString():String {
            var s:String = String(int(fps));
            if (fps < 20) {
                s += "." + String(int(fps * 10) % 10);
            }
            if (fps < 2) {
                s += String(int(fps * 100) % 10);
            }
            return s + "fps";
        }
        
        public function infoString():String {
            var text:String = "frame " + String(clock.currentCount);
            text += " : " + String(int(t)) + "." + String(int(t * 10) % 10) + "s";
            text += " : " + fpsString();
            return text;
        }
        
        public function toggle():void {
            if (clock.running) clock.stop();
            else clock.start();
        }
    }
}

